#ifndef __IM_VALUE_IMPL_H__
#define __IM_VALUE_IMPL_H__
/**
 * @defgroup IMValueImpl
 * @ingroup PrivateIMBus
 * @{
 */

/** @struct IMValueImpl
 *  @brief  Real implementation used by IMValue and IMValueArray.
 */

IM_BEGIN_DECLS

typedef struct _IMValueImpl     IMValueImpl;

struct _IMValueImpl
{
    IMUInt      type   : 31;
    IMUInt      nocopy : 1;

    union {
        IMInt16     v_int16;
        IMUInt16    v_uint16;
        IMInt32     v_int32;
        IMUInt32    v_uint32;
        IMInt64     v_int64;
        IMUInt64    v_uint64;
        IMDouble    v_double;
        IMPointer   v_pointer;
    } data;
};

#define im_value_impl_init(impl)                                            \
    do {                                                                    \
        (impl)->type   = IM_TYPE_INVALID;                                   \
        (impl)->nocopy = 0;                                                 \
        memset (&((impl)->data), 0, sizeof ((impl)->data));                 \
    } while (0)

#define im_value_impl_clear(impl)                                           \
    do {                                                                    \
        if ((impl)->type == IM_TYPE_C_STRING && !(impl)->nocopy)            \
            free ((impl)->data.v_pointer);                                  \
        else if (IM_TYPE_IS_OBJECT((impl)->type))                           \
            im_object_unref ((impl)->data.v_pointer);                       \
        im_value_impl_init(impl);                                           \
    } while (0)

#define im_value_impl_value_type(impl)  ((impl)->type)

#define im_value_impl_copy(dest,src)                                        \
    do {                                                                    \
        if ((dest)->type != IM_TYPE_INVALID)                                \
            im_value_impl_clear(dest);                                      \
        (dest)->type   = (src)->type;                                       \
        (dest)->nocopy = (src)->nocopy;                                     \
        (dest)->data   = (src)->data;                                       \
        if ((src)->type == IM_TYPE_C_STRING && !(src)->nocopy)              \
            (dest)->data.v_pointer = strdup ((src)->data.v_pointer);        \
        else if (IM_TYPE_IS_OBJECT((src)->type))                            \
            (dest)->data.v_pointer =                                        \
                im_object_ref (im_object_clone((src)->data.v_pointer));     \
    } while(0)

#define im_value_impl_set_fundamental(impl,t,m,v)                           \
    do {                                                                    \
        if ((impl)->type != IM_TYPE_INVALID)                                \
            im_value_impl_clear(impl);                                      \
        (impl)->type = (t);                                                 \
        (impl)->data.m = (v);                                               \
    } while (0)

#define im_value_impl_get_fundamental(impl,t,ct,m)                          \
    (((impl)->type == (t)) ? ((ct)(impl)->data.m) : 0)

#define im_value_impl_set_char(impl,v)                                      \
    im_value_impl_set_fundamental(impl,IM_TYPE_CHAR,v_int32,v)
#define im_value_impl_get_char(impl)                                        \
    im_value_impl_get_fundamental(impl,IM_TYPE_CHAR,IMChar,v_int32)

#define im_value_impl_set_uchar(impl,v)                                     \
    im_value_impl_set_fundamental(impl,IM_TYPE_UCHAR,v_uint32,v)
#define im_value_impl_get_uchar(impl)                                       \
    im_value_impl_get_fundamental(impl,IM_TYPE_UCHAR,IMUChar,v_uint32)

#define im_value_impl_set_bool(impl,v)                                      \
    im_value_impl_set_fundamental(impl,IM_TYPE_BOOL,v_int32,v)
#define im_value_impl_get_bool(impl)                                        \
    im_value_impl_get_fundamental(impl,IM_TYPE_BOOL,IMBool,v_int32)

#define im_value_impl_set_int16(impl,v)                                     \
    im_value_impl_set_fundamental(impl,IM_TYPE_INT16,v_int16,v)
#define im_value_impl_get_int16(impl)                                       \
    im_value_impl_get_fundamental(impl,IM_TYPE_INT16,IMInt16,v_int16)

#define im_value_impl_set_uint16(impl,v)                                    \
    im_value_impl_set_fundamental(impl,IM_TYPE_UINT16,v_uint16,v)
#define im_value_impl_get_uint16(impl)                                      \
    im_value_impl_get_fundamental(impl,IM_TYPE_UINT16,IMUInt16,v_uint16)

#define im_value_impl_set_int32(impl,v)                                     \
    im_value_impl_set_fundamental(impl,IM_TYPE_INT32,v_int32,v)
#define im_value_impl_get_int32(impl)                                       \
    im_value_impl_get_fundamental(impl,IM_TYPE_INT32,IMInt32,v_int32)

#define im_value_impl_set_uint32(impl,v)                                    \
    im_value_impl_set_fundamental(impl,IM_TYPE_UINT32,v_uint32,v)
#define im_value_impl_get_uint32(impl)                                      \
    im_value_impl_get_fundamental(impl,IM_TYPE_UINT32,IMUInt32,v_uint32)

#define im_value_impl_set_int64(impl,v)                                     \
    im_value_impl_set_fundamental(impl,IM_TYPE_INT64,v_int64,v)
#define im_value_impl_get_int64(impl)                                       \
    im_value_impl_get_fundamental(impl,IM_TYPE_INT64,IMInt64,v_int64)

#define im_value_impl_set_uint64(impl,v)                                    \
    im_value_impl_set_fundamental(impl,IM_TYPE_UINT64,v_uint64,v)
#define im_value_impl_get_uint64(impl)                                      \
    im_value_impl_get_fundamental(impl,IM_TYPE_UINT64,IMUInt64,v_uint64)

#define im_value_impl_set_double(impl,v)                                    \
    im_value_impl_set_fundamental(impl,IM_TYPE_DOUBLE,v_double,v)
#define im_value_impl_get_double(impl)                                      \
    im_value_impl_get_fundamental(impl,IM_TYPE_DOUBLE,IMDouble,v_double)

#define im_value_impl_set_pointer(impl,v)                                   \
    im_value_impl_set_fundamental(impl,IM_TYPE_POINTER,v_pointer,v)
#define im_value_impl_get_pointer(impl)                                     \
    im_value_impl_get_fundamental(impl,IM_TYPE_POINTER,IMPointer,v_pointer)

#define im_value_impl_set_c_string(impl,v)                                  \
    im_value_impl_set_fundamental(impl,IM_TYPE_C_STRING,v_pointer,strdup(v))
#define im_value_impl_take_c_string(impl,v)                                 \
    im_value_impl_set_fundamental(impl,IM_TYPE_C_STRING,v_pointer,(IMChar*)v)
#define im_value_impl_set_static_c_string(impl,v)                           \
    do {                                                                    \
        im_value_impl_set_fundamental(impl,IM_TYPE_C_STRING,v_pointer,(IMChar*)v);\
        (impl)->nocopy = 1;                                                 \
    } while (0)
#define im_value_impl_get_c_string(impl)                                    \
    im_value_impl_get_fundamental(impl,IM_TYPE_C_STRING,IMChar*,v_pointer)
#define im_value_impl_dup_c_string(impl)                                    \
    (((impl)->type == IM_TYPE_C_STRING) ? strdup((impl)->data.v_pointer) : 0)

#define im_value_impl_set_object(impl,v)                                    \
    do {                                                                    \
        if ((impl)->type != IM_TYPE_INVALID)                                \
            im_value_impl_clear(impl);                                      \
        (impl)->type = im_object_get_type(v);                               \
        (impl)->data.v_pointer = (v);                                       \
        im_object_ref(v);                                                   \
    } while (0)

#define im_value_impl_get_object(impl)                                      \
    (IM_TYPE_IS_OBJECT((impl)->type) ? ((impl)->data.v_pointer) : 0)
#define im_value_impl_dup_object(impl)                                      \
    (IM_TYPE_IS_OBJECT((impl)->type) ? im_object_clone((impl)->data.v_pointer) : 0)

IMBool          __im_value_impl_serialize       (const IMValueImpl      *impl,
                                                 IMStream               *stream);
IMBool          __im_value_impl_deserialize     (IMValueImpl            *impl,
                                                 IMStream               *stream);

IMValueImpl*    __im_value_get_impl             (IMConstPointer          value);
void            __im_value_set_impl             (IMPointer               value,
                                                 const IMValueImpl      *impl);

IM_END_DECLS
/** @} */

#endif
/*
vi:ts=4:nowrap:ai:expandtab
*/
